package cn.yjh.server.net;

import java.io.IOException;
import java.net.URL;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ExecutorService;

import cn.yjh.exception.ServiceNotFoundException;
import cn.yjh.server.protocol.ProtocolHandler;
import cn.yjh.server.protocol.http.HttpProtocolHandler;
import cn.yjh.server.protocol.RPCProtocolHandler;
import cn.yjh.server.support.HttpHeader;
import cn.yjh.server.support.HttpStatus;
import cn.yjh.support.ServiceHandler;
import cn.yjh.utils.ByteBufferUtils;
import cn.yjh.server.support.Constants;
import cn.yjh.server.support.Request;
import cn.yjh.server.support.Response;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class DefaultHandler extends AbstractHandler {

    Logger logger = LoggerFactory.getLogger(DefaultHandler.class);

    // 从 reactor 的序号
    private int num;

    private final SelectionKey selectionKey;

    private final SocketChannel socketChannel;

    private Request request;

    private Response response;

    private ProtocolHandler protocolHandler = null;

    private byte preChr, chr = 0;

    private int startIndex = 0;

    private int endIndex = 0;

    private int RS = 0;

    DefaultHandler(SlaveReactor reactor, Thread reactorThread, SocketChannel socketChannel,
                   SelectionKey selectionKey, int num, ExecutorService workers,
                   ServiceHandler serviceHandler) throws IOException {
        super(reactor,reactorThread, workers, serviceHandler);
        // 用于区分 Handler 被哪个 slave reactor 执行
        this.num = num;
        // 接收客户端连接
        this.socketChannel = socketChannel;
        this.selectionKey = selectionKey;
        request = new Request(this.socketChannel,this.inCache);
        response = new Response(this.outCache);
    }

    @Override
    public void read() {
        int st = 0;
        if (selectionKey.isValid()) {
            while(true){
                try{
                    int len = 0;
                    if(RS == 0 || RS == 1 || RS == 2){
                         len = socketChannel.read(inCache);
                    }
                    // 如果客户端正常关闭了 socket,那么再次读取返回的是 -1
                    if(len == -1){
                        logger.info("client closed the socket !");
                        selectionKey.cancel();
                        return;
                    }
                    // 若是没有可接受的数据了，直接跳出循环，避免 cpu 空转
                    if(len == 0)
                        break;
                    try{
                        // 根据状态判断请求行是否已经解析完成了
                        if(RS == 0 || RS == 1 || RS == 2){
                            // 解析请求行
                            st = parseRequestLine();
                        }
                    }catch (Exception e){
                        logger.error("parse request line exception: {}",e);
                        selectionKey.cancel();
                        break;
                    }
                    // 将未解析的数据往缓存前面移动
                    //ByteBufferUtils.resetByteBuffer(inCache,endIndex,inCache.limit());
                    if(protocolHandler != null){
                        protocolHandler.decode();
                        break;
                    }
                }catch (IOException e){
                    logger.error("client exception: {}",e);
                    selectionKey.cancel();
                    return;
                }
            }

            if(st == 3){
                if(logger.isDebugEnabled()){
                    logger.debug("slave reactor {}, Read size:[ {} ]",num,inCache.limit());
                }
                // 将当前状态设置为: 待处理
                status = PROCESS;
                // 设置当前 SelectionKey 关注写就绪事件
                selectionKey.interestOps(SelectionKey.OP_WRITE);
            }
        }
    }

    @Override
    public void write() {
        if (selectionKey.isValid()) {
            try {
                // 调用协议处理器执行编码
                protocolHandler.encode(response);

                outCache.flip();
                int count = socketChannel.write(outCache);

                if(logger.isDebugEnabled()){
                    logger.debug("slave reactor {}, Write size:[ {} ]",num,outCache.position());
                }
                //socketChannel.shutdownOutput();
                if (count <= 0) {
                    //同上，write场景下，取到-1，也意味着客户端断开连接
                    selectionKey.cancel();
                    socketChannel.close();
                }
                // 请求处理完后，将 reactor 阻塞住。避免 CPU 负载过高
                reactor.setStatus("wait");

                // 根据请求头判断是否长连接
                if("keep-alive".equals(request.getHeader().get("Connection"))){
                    //长连接，则再次切换到读
                    status = READ;

                    RS = 0;

                    //重新设置为读
                    selectionKey.interestOps(SelectionKey.OP_READ);
                }else{
                    selectionKey.cancel();
                }
                // 重置缓存和指针
                inCache.clear();
                endIndex = 0;
                startIndex = 0;
            } catch (IOException e) {
                selectionKey.cancel();
                try {
                    socketChannel.close();
                } catch (IOException e1) {
                    logger.info("close socket channel exception: {}",e1);
                }
            }
        }
    }

    @Override
    public void doProcess() {
        if(request != null){
            try {
                serviceHandler.process(request,response);
            } catch (ServiceNotFoundException e) {
                URL resource = Thread.currentThread().getContextClassLoader().getResource(request.getUrl().substring(1));
                if(resource !=null ){
                    response.setStatus(HttpStatus.OK);
                    response.getHeader().put(HttpHeader.CONTENT_TYPE.VALUE,"text/html;charset=UTF-8");
                    response.getHeader().put(HttpHeader.CONTENT_DISPOSITION.VALUE,"inline");
                    response.setResourceURL(resource);
                }else{
                    logger.error("{}",e);
                    response.setStatus(HttpStatus.NOT_FOUND);
                    response.setMsg(e.getMessage());
                }
            }
        }else{
            logger.error("decoding faild");
            response.setStatus(HttpStatus.SERVER_ERROR);
            response.setMsg("decoding faild!");
        }
        // 将当前状态设置为写出就绪状态
        status = WRITE;
    }

    private int parseRequestLine(){
        inCache.flip();
        if(RS == 0){
            // 解析请求行的：method 类型
            while (inCache.hasRemaining()){
                chr = inCache.get();
                endIndex = inCache.position();
                if(chr == Constants.SP || chr == Constants.HT){
                    request.setMethod(new String(inCache.array(), startIndex, endIndex-startIndex-1, StandardCharsets.UTF_8));
                    startIndex = endIndex;
                    RS = 1;
                    break;
                }
            }
            if(!inCache.hasRemaining() && RS == 0){
                ByteBufferUtils.resetByteBuffer(inCache,startIndex,endIndex);
                startIndex = 0;
                return RS;
            }
        }
        if(RS == 1){
            // 解析请求的：URL
            while (inCache.hasRemaining()){
                chr = inCache.get();
                endIndex = inCache.position();
                if(chr == Constants.SP || chr == Constants.HT){
                    request.setUrl(new String(inCache.array(), startIndex, endIndex-startIndex-1, StandardCharsets.UTF_8));
                    startIndex = endIndex;
                    RS = 2;
                    break;
                }
            }
            if(!inCache.hasRemaining() && RS == 1){
                if((endIndex -startIndex) == inCache.limit()){
                    logger.info("需要扩容");
                    ByteBufferUtils.expandByteBufferCapacity(inCache,2);
                }else{
                    ByteBufferUtils.resetByteBuffer(inCache,startIndex,endIndex);
                }
                startIndex = 0;
                return RS;
            }
        }
        if(RS == 2){
            // 解析请求的：协议
            while (inCache.hasRemaining()){
                preChr = chr;
                chr = inCache.get();
                endIndex = inCache.position();
                if(preChr == Constants.CR && chr == Constants.LF){
                    String protocolString = new String(inCache.array(), startIndex, endIndex-startIndex-2, StandardCharsets.UTF_8);
                    if(protocolString.indexOf("RPC") != -1){
                        protocolHandler = new RPCProtocolHandler(request,response);
                    }else{
                        protocolHandler = new HttpProtocolHandler(request,response);
                    }
                    startIndex = endIndex;
                    RS = 3;
                    break;
                }
            }
            if(!inCache.hasRemaining() && RS == 2){
                ByteBufferUtils.resetByteBuffer(inCache,startIndex,endIndex);
                startIndex = 0;
                return RS;
            }
        }
        return RS;
    }

}
